/*
 *  ReadImageFile.cpp
 *  Ray Tracing
 *
 *  Created by Jean-Marc Comby on Sat Jun 05 2004.
 *  Copyright (c) 2004. All rights reserved.
 *
 */

#include "ReadImageFile.hpp"

#include "pngwriter.hpp"

using boost::progress_display;

ComposantCouleur *litpng(const char *filename, int &height, int &width)
{
  std::cout << "Chargement de l image " << filename << std::endl;

  pngwriter PngImage;

  PngImage.readfromfile( filename );

  unsigned sizeH( PngImage.getheight() ), sizeW( PngImage.getwidth() );

  height = int( sizeH );
  width  = int( sizeW );

  ComposantCouleur * resultat = new ComposantCouleur[ 3u * sizeH * sizeW ];

  unsigned i, j;

  if ( sizeof( ComposantCouleur ) == 1 )
    {
      for ( i = 0; i < sizeH; i++ )
	{
	  for ( j = 0; j < sizeW; j++ )
	    {
	      resultat[ i * sizeW + j + 0 ] = PngImage.cread( i, j, pngwriter::tRed );
	      resultat[ i * sizeW + j + 1 ] = PngImage.cread( i, j, pngwriter::tGreen );
	      resultat[ i * sizeW + j + 2 ] = PngImage.cread( i, j, pngwriter::tBlue );
	    }
	}
    }
  else if ( sizeof( ComposantCouleur ) == 2 )
    {
      for ( i = 0; i < sizeH; i++ )
	{
	  for ( j = 0; j < sizeW; j++ )
	    {
	      resultat[ i * sizeW + j + 0 ] = PngImage.read( i, j, pngwriter::tRed );
	      resultat[ i * sizeW + j + 1 ] = PngImage.read( i, j, pngwriter::tGreen );
	      resultat[ i * sizeW + j + 2 ] = PngImage.read( i, j, pngwriter::tBlue );
	    }
	}
    }

  return resultat;
  
  // ComposantCouleur *b, *pb;
  // png_structp png_ptr;
  // png_infop info_ptr;
  // //unsigned int sig_read = 0;
  // char buf[PNG_BYTES_TO_CHECK];
	
  // // ouvre le fichier
  // FILE *fp=fopen(filename, "rb");
  // if (!fp)
  //   {
  //     Erreur err(true,1,"Probleme d ouverture du fichier","Fichier LirePng");
  //     err.ecrire("Erreur.txt");
  //     std::cerr << "Crash du programme. Consulter le log pour plus d'info." << std::endl;
  //     exit(1);
  //   }
	
  // // Verifie l en-tete (si png ou non)
  // if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
  //   {
  //     Erreur err(true,1,"Impossible de verifier l en-tete","Fichier LirePng");
  //     err.ecrire("Erreur.txt");
  //     std::cerr << "Crash du programme. Consulter le log" << std::endl;
  //     exit(1);
  //   }
  // /*int is_png(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
  //   if (is_png!=0)
  //   {
  //   Erreur err(true,1,"Pas un fichier png","Fichier LirePng");
  //   err.ecrire("Erreur.txt");
  //   std::cerr << "Crash du programme. Consulter le log" << std::endl;
  //   exit(1);
  //   }*/
	
  // /* Create and initialize the png_struct with the desired error handler
  //  * functions.  If you want to use the default stderr and longjump method,
  //  * you can supply NULL for the last three parameters.  We also supply the
  //  * the compiler header file version, so that we know if the application
  //  * was compiled with a compatible version of the library.  REQUIRED
  //  */
	
  // png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
  // if (png_ptr == NULL)
  //   {
  //     fclose(fp);
  //     Erreur err(true,1,"Erreur d initialisation du png","Fichier LirePng");
  //     err.ecrire("Erreur.txt");
  //     std::cerr << "Can't initialize PNG file for reading" << std::endl;
  //     exit(1);
  //   }
	
  // /* Allocate/initialize the memory for image information.  REQUIRED. */
  // info_ptr = png_create_info_struct(png_ptr);
  // if (info_ptr == NULL)
  //   {
  //     fclose(fp);
  //     png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
  //     Erreur err(true,1,"Impossible d alouer de la memoire","Fichier LirePng");
  //     err.ecrire("Erreur.txt");
  //     std::cerr << "Can't allocate memory to read PNG file" << std::endl;
  //     exit(1);
  //   }
	
  // /* Set error handling if you are using the setjmp/longjmp method (this is
  //  * the normal method of doing things with libpng).  REQUIRED unless you
  //  * set up your own error handlers in the png_create_read_struct() earlier.
  //  */
	
  // if (setjmp(png_jmpbuf(png_ptr)))
  //   {
  //     /* Free all of the memory associated with the png_ptr and info_ptr */
  //     png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
  //     fclose(fp);
  //     /* If we get here, we had a problem reading the file */
  //     Erreur err(true,1,"Probleme de lecture du png","Fichier LirePng");
  //     err.ecrire("Erreur.txt");
  //     std::cerr << "Exception occurred while reading PNG file" << std::endl;
  //     exit(1);
  //   }
	
  // /* Set up the input control if you are using standard C streams */
	
  // png_init_io(png_ptr, fp);
	
  // png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
	
  // /*
  //  * If you have enough memory to read in the entire image at once,
  //  * and you need to specify only transforms that can be controlled
  //  * with one of the PNG_TRANSFORM_* bits (this presently excludes
  //  * dithering, filling, setting background, and doing gamma
  //  * adjustment), then you can read the entire image (including
  //  * pixels) into the info structure with this call:
  //  */
	
  // png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL );
  // // on supprime la composante alpha de certain fichier png pour chaque pixel
	
  // // nombre de channel par couleur (maximum 3 channel)
  // int numChannels = png_get_channels(png_ptr, info_ptr);
	
  // if (png_get_bit_depth(png_ptr, info_ptr) != 8)
  //   {
  //     Erreur err(true,1,"Fichier pas en rvb","Fichier LirePng");
  //     err.ecrire("Erreur.txt");
  //     std::cerr << "Can't handle PNG files with bit depth other than 8.  '" << filename
  // 		<< "' has " << png_get_bit_depth(png_ptr, info_ptr) << " bits per pixel." << std::endl;
  //     exit(1);
  //   }
	
  // // hauteur et largeur de l'image
  // width = png_get_image_width(png_ptr,info_ptr);
  // height = png_get_image_height(png_ptr,info_ptr);
	
  // int imageSize=3*width*height;
	
  // b = pb = new ComposantCouleur[ imageSize ];
	
  // for (int r(0); r<(int)info_ptr->height; r++) {
  //   png_bytep row = info_ptr->row_pointers[r];
  //   int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  //   for (int c=0; c < rowbytes; c++)
  //     switch (numChannels) {
  //     case 1:
  // 	*(pb)++ = row[c];
  // 	*(pb)++ = row[c];
  // 	*(pb)++ = row[c];
  // 	break;
  //     case 2:
  // 	std::cerr << "Can't handle a two-channel PNG file: " << filename << std::endl;
  // 	exit(-1);
  // 	break;
  //     case 3:
  //     case 4: // en theorie impossible d avoir quatre
  // 	*(pb)++ = row[c];
  // 	break;
  //     }
  // }
		
  // // Clean up PNG stuff
  // png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
  // fclose(fp);
  // return b;
}

ComposantCouleur *litJpeg(const char *filename, int &height, int &width)
{
  std::cout << "Chargement de l image " << filename << std::endl;
  /* This struct contains the JPEG decompression parameters and pointers to
   * working space (which is allocated as needed by the JPEG library).
   */
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
	
  /* More stuff */
  FILE * infile;		/* source file */
	
  /* In this example we want to open the input file before doing anything else,
   * so that the setjmp() error recovery below can assume the file is open.
   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
   * requires it in order to read binary files.
   */
	
  if ((infile = fopen(filename, "rb")) == NULL) {
    Erreur err(true,1,"Probleme d ouverture du fichier","Fichier LireJpeg");
    err.ecrire("Erreur.txt");
    std::cerr << "Crash du programme. Fichier impossible a ouvrir." << std::endl;
    exit(1);
  }
  /* Step 1: allocate and initialize JPEG decompression object */
	
  cinfo.err = jpeg_std_error(&jerr);
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress(&cinfo);
	
  /* Step 2: specify data source (eg, a file) */
	
  jpeg_stdio_src(&cinfo, infile);
	
  // on verifie si c est un jpeg
  if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK)
    {
      jpeg_destroy_decompress(&cinfo);
      fclose(infile);
      Erreur err(true,1,"Pas un fichier Jpeg","Fichier LireJpeg");
      err.ecrire("Erreur.txt");
      std::cerr << "Crash du programme. Consulter le log" << std::endl;
      exit(1);
    }
	
  // pointeurs sur mon futur tableau
  ComposantCouleur *Data;
  unsigned char *Ptr;
	
  /* Step 5: Start decompressor */
	
  jpeg_start_decompress(&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */
  height=cinfo.image_height;
  width=cinfo.image_width;
	
  long loops(height);
  progress_display pd( loops ); // affiche la barre de progression
	
  if (cinfo.output_components!=3) // on elimine ici les jpeg en gris, ou autre pas rvb
    {
      jpeg_destroy_decompress(&cinfo);
      fclose(infile);
      Erreur err(true,1,"Pas un fichier en rvb","Fichier LireJpeg");
      err.ecrire("Erreur.txt");
      std::cerr << "Crash du programme. Consulter le log" << std::endl;
      exit(1);
    }
  // allocation mem de mon image
  Data = new ComposantCouleur[width * height * 3];
  Ptr = new unsigned char[width * height * 3];
	
  // lecture de l image
  for (int n = 0; n<height; n++)
    {
      jpeg_read_scanlines(&cinfo, &Ptr, 1);
      Ptr += width * 3;
      ++pd; // permet de faire progresser la barre
    }
	
  /* Step 7: Finish decompression */
	
  (void) jpeg_finish_decompress(&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */
	
  /* Step 8: Release JPEG decompression object */
	
  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress(&cinfo);
	
  /* After finish_decompress, we can close the input file.
   * Here we postpone it until after no more JPEG errors are possible,
   * so as to simplify the setjmp error logic above.  (Actually, I don't
   * think that jpeg_destroy can do an error exit, but why assume anything...)
   */
  fclose(infile);

  for ( unsigned i( 0 ), total( width * height * 3 ); i < total; i++ )
    {
      *( Data + i ) = static_cast< int >( *( Ptr + i ) );
    }

  delete [] Ptr;

  return Data;
}

Image convertImage(ComposantCouleur *tab, const int &height, const int &width)
{
  std::cout << "Conversion de l image" << std::endl;
  Image retour(width,height);
  ComposantCouleur rouge,vert,bleu;
  int compteur(0);
  for (int pixel_y(0); pixel_y < height; pixel_y++)
    {
      for (int pixel_x(0); pixel_x < width; pixel_x++)
	{
	  rouge=tab[compteur];
	  compteur++;
	  vert=tab[compteur];
	  compteur++;
	  bleu=tab[compteur];
	  compteur++;
	  retour.setPixel(pixel_y,pixel_x,Couleur(rouge,vert,bleu));
	}
    }
  delete [] tab;
  return retour;
}
